import Stage from '.';
import Animation from '../animation';
import { debounce, toPx } from '@/utils';
import {
  onWindowMousemove,
  onWindowDragover,
  onWindowMouseup,
  onWindowKeydown,
  onWindowKeyup,
  onCopy,
  onCut,
  onPaste,
  onMousemove,
  onMousedown,
  onMouseup,
  onDblclick,
  onContextmenu,
  onWheel,
  onKeydown,
  onKeyup,
  onScrollbar,
  onScrollbarEnd,
  onStageDrag,
  onStageDragEnd,
  onNodeDrag,
  onNodeDragEnd,
  onRegion,
  onRegionEnd,
  onEdge,
  onEdgeEnd,
} from './evnet';

/**
 * 初始化
 * @this {Stage}
 */
export default function init() {
  this.FPS(this.fps); // 设置 FPS
  this.handleRecord = debounce(this._handleRecord.bind(this), 200, { maxWait: 1000 }); // 记录画布历史状态函数防抖
  this.history.push(this.toSchema()); // 记录初始历史状态
  this.lastOffset = { ...this.offset }; // 记录上一次的偏移量
  this.lastScale = this.scale; // 记录上一次的缩放值
  // 创建 designer 元素并添加到 container 元素中
  this.designerEl = this.containerEl.appendChild(document.createElement('div'));
  this.designerEl.className = 'designer-container';
  this.designerEl.setAttribute('style', 'position:relative;user-select:none;overflow:hidden;width:100%;height:100%');
  // 将 canvas 元素添加到 designer 元素中
  this.designerEl.appendChild(this.canvas.el);
  this.ctx = this.canvas.getContext();
  // 根据 container 元素自动设置宽高
  if (this.autoSize) {
    this.setContainerSize(false);
    // 监听 container 元素样式变化（行内样式改变才能生效）
    const observer = new MutationObserver(() => this.setContainerSize(true));
    observer.observe(this.containerEl, { attributes: true });
  }
  // 监听视口变化
  window.addEventListener('resize', () => this.updatePixelRatio(), { signal: this.abortController.signal });
  // 初始化事件
  initEvents.call(this);
  // 监听并发布所有画布行为
  const allAction = () => this.emit('allAction', this);
  this.on('action', allAction); // 监听画布行为（不包括画布拖动、缩放、移动、节点拖动）
  this.on('drag', allAction); // 监听画布拖动
  this.on('move', allAction); // 监听画布缩放
  this.on('scale', allAction); // 监听画布移动
  this.on('nodeDrag', allAction); // 监听节点拖动
  this.on('nodeMove', allAction); // 监听节点移动
  // 实例化全局动画对象并执行
  new Animation((frame) => {
    Object.assign(this.frame, frame); // 更新动画帧信息
    const { edging, allEffectEdges } = this;
    // 节点连线中状态 或 有受影响的节点连线 触发绘制
    if (edging || allEffectEdges.length) return true;
    // 否则 不触发绘制
    return false;
  }, this).start();
}

/**
 * 初始化事件
 * @this {Stage}
 */
function initEvents() {
  if (!this.eventEnabled) return;
  const { signal } = this.abortController;
  // 客户端鼠标移动事件
  this.onWindowMousemove = onWindowMousemove.bind(this);
  window.addEventListener('mousemove', this.onWindowMousemove, { signal, capture: true });
  // 客户端拖动中事件
  this.onWindowDragover = onWindowDragover.bind(this);
  window.addEventListener('dragover', this.onWindowDragover, { signal, capture: true });
  // 客户端鼠标弹起事件
  this.onWindowMouseup = onWindowMouseup.bind(this);
  window.addEventListener('mouseup', this.onWindowMouseup, { signal });
  // 客户端键盘按下事件
  this.onWindowKeydown = onWindowKeydown.bind(this);
  window.addEventListener('keydown', this.onWindowKeydown, { signal });
  // 客户端键盘释放事件
  this.onWindowKeyup = onWindowKeyup.bind(this);
  window.addEventListener('keyup', this.onWindowKeyup, { signal });
  // 客户端键盘按下事件
  this.onCopy = onCopy.bind(this);
  window.addEventListener('copy', this.onCopy, { signal });
  // 客户端键盘释放事件
  this.onCut = onCut.bind(this);
  window.addEventListener('cut', this.onCut, { signal });
  // 客户端键盘释放事件
  this.onPaste = onPaste.bind(this);
  window.addEventListener('paste', this.onPaste, { signal });
  // 鼠标移动事件
  this.onMousemove = onMousemove.bind(this);
  this.canvas.el.addEventListener('mousemove', this.onMousemove, { signal });
  // 鼠标按下事件
  this.onMousedown = onMousedown.bind(this);
  this.canvas.el.addEventListener('mousedown', this.onMousedown, { signal });
  // 鼠标弹起事件
  this.onMouseup = onMouseup.bind(this);
  this.canvas.el.addEventListener('mouseup', this.onMouseup, { signal });
  // 鼠标双击事件
  this.onDblclick = onDblclick.bind(this);
  this.canvas.el.addEventListener('dblclick', this.onDblclick, { signal });
  // 打开上下文菜单事件
  this.onContextmenu = onContextmenu.bind(this);
  this.canvas.el.addEventListener('contextmenu', this.onContextmenu, { signal });
  // 滚动鼠标滚轮或类似的输入设备时触发的事件
  this.onWheel = onWheel.bind(this);
  this.canvas.el.addEventListener('wheel', this.onWheel, { signal });
  // 键盘按下事件
  this.onKeydown = onKeydown.bind(this);
  this.canvas.el.addEventListener('keydown', this.onKeydown, { signal });
  // 键盘弹起事件
  this.onKeyup = onKeyup.bind(this);
  this.canvas.el.addEventListener('keyup', this.onKeyup, { signal });
  // 滚动条操作相关
  this.onScrollbar = onScrollbar.bind(this);
  this.onScrollbarEnd = onScrollbarEnd.bind(this);
  // 画布拖动相关
  this.onStageDrag = onStageDrag.bind(this);
  this.onStageDragEnd = onStageDragEnd.bind(this);
  // 节点拖动相关
  this.onNodeDrag = onNodeDrag.bind(this);
  this.onNodeDragEnd = onNodeDragEnd.bind(this);
  // 框选相关
  this.onRegion = onRegion.bind(this);
  this.onRegionEnd = onRegionEnd.bind(this);
  // 连线相关
  this.onEdge = onEdge.bind(this);
  this.onEdgeEnd = onEdgeEnd.bind(this);
  // 初始化文本编辑元素
  initTextareaEl.call(this);
}

/**
 * 初始化文本编辑元素
 * @this {Stage}
 */
function initTextareaEl() {
  const { textareaEl } = this;
  // @ts-ignore 绑定更新事件
  textareaEl.update = updateTextareaEl.bind(this);
  textareaEl.className = 'designer-textarea';
  textareaEl.setAttribute(
    'style',
    `position: fixed;
    border: none;
    padding: 0px;
    margin: 0px;
    word-break: break-all;
    overflow: hidden;
    background: transparent;
    outline: none;
    resize: none;
    transform-origin: left top;
    color: transparent;
    caret-color: #000;`,
  );
  textareaEl.spellcheck = false;
  const { signal } = this.abortController;
  // 值变化事件
  textareaEl.addEventListener(
    'input',
    (e) => {
      // @ts-ignore
      this.editTextNode?.setText(e.target.value, false);
      // @ts-ignore 更新文本编辑元素
      textareaEl.update();
    },
    { signal },
  );
  // 滚轮事件 代理画布滚轮事件
  textareaEl.addEventListener('wheel', (e) => (e.preventDefault(), this.onWheel(e)), { signal });
  // 鼠标按下事件 中键时 代理画布鼠标按下事件
  textareaEl.addEventListener('mousedown', (e) => e.button === 1 && this.onMousedown(e), { signal });
  // 键盘按下事件 esc 触发失焦
  textareaEl.addEventListener('keydown', (e) => e.key === 'Escape' && textareaEl.blur(), { signal });
  // @ts-ignore 获得焦点事件 更新文本编辑元素
  textareaEl.addEventListener('focus', () => textareaEl.update(), { signal });
  // 失去焦点事件
  textareaEl.addEventListener(
    'blur',
    () => {
      // 清除当前编辑的文本节点
      this.editTextNode = null;
      // 移除文本编辑元素
      this.textareaEl.remove();
      // 记录历史状态
      this.handleRecord();
    },
    { signal },
  );
}

/**
 * 更新文本编辑元素
 * @this {Stage}
 */
function updateTextareaEl() {
  const { editTextNode, textareaEl } = this;
  if (!editTextNode) return;
  const { width, height, fontSize, lineHeight, letterSpacing, verticalAlign } = editTextNode;
  const { style } = textareaEl;
  // 同步文本样式
  editTextNode.syncStyle(textareaEl);
  // 根据节点相对坐标获取画布全局坐标
  let { fixed, rotate, scale } = editTextNode.getGlobalCoord({ x: 0, y: 0 });
  style.left = toPx(fixed.x);
  style.top = toPx(fixed.y);
  style.width = toPx(width * 1.0001); // 实际 textarea 宽度放大一定比例，防止 Mac 系统文本编辑时意外换行
  style.height = toPx(height);
  // 适应文本垂直对齐方式
  const interval = (lineHeight - fontSize) / 2;
  let translateY = { top: -interval, bottom: interval }[verticalAlign] || 0;
  // 字体大小小于12时，浏览器只会显示12px的字体，需要调整文本编辑元素
  if (fontSize < 12) {
    const offsetScale = fontSize / 12;
    scale *= offsetScale;
    style.lineHeight = toPx(lineHeight / offsetScale);
    style.letterSpacing = toPx(letterSpacing / offsetScale);
    style.width = toPx(width / offsetScale);
    style.height = toPx(height / offsetScale);
  }
  style.transform = `rotate(${rotate}deg) scale(${scale}) translateY(${toPx(translateY)})`;
}
